

#include <iostream>
#include <set>
#include "spdlog/spdlog.h"
#include "spdlog/sinks/rotating_file_sink.h"
#include "spdlog/sinks/udp_sink.h"
#include "spdlog/sinks/stdout_sinks.h"
#include "spdlog/sinks/stdout_color_sinks.h"
#include "log_service.h"
#include "log_service_impl.h"

#define DEFAULT_LOGGER_PATTERN "%^[%Y-%m-%d %H:%M:%S.%e][%n][%l] %v%$"

#define DEFAULT_LOGGER_FILE_PATH "run.log"
#define DEFAULT_LOGGER_FILE_SIZE_MB 10
#define DEFAULT_LOGGER_FILE_COUNT 10

#define DEFAULT_LOGGER_IP "127.0.0.1"
#define DEFAULT_LOGGER_PORT 3768


LogServiceImpl::LogServiceImpl():pattern_(DEFAULT_LOGGER_PATTERN)
{
}

LogServiceImpl::~LogServiceImpl()
{
}

LogServiceImpl &LogServiceImpl::instance()
{
    static LogServiceImpl instance_;
    return instance_;
}

std::shared_ptr<spdlog::logger> LogServiceImpl::create(const std::string &tag, spdlog::level::level_enum level)
{
    std::lock_guard<std::mutex> lock(lock_);
    if (sinks_.size() == 0)
    {
        // std::cerr << "create logger failed: please call init() first!" << std::endl;
        return nullptr;
    }
    auto logger = std::make_shared<spdlog::logger>(tag, sinks_.begin(), sinks_.end());
    if (logger) {
        logger->set_level(level);
    }
    return logger;
}

int LogServiceImpl::init(std::set<LogService::LogType> &log_types)
{
    std::lock_guard<std::mutex> lock(lock_);
    if (log_types.empty()) {
        return -1;
    }

    if (!sinks_.empty())
    {
        /* already initialized */
        return -2;
    }

    try
    {
        for (auto &type : log_types)
        {
            if (type == LogService::STDOUT_LOG)
            {
                auto stdout_sink = std::make_shared<spdlog::sinks::stdout_sink_mt>();
                if (stdout_sink)
                {
                    sinks_.push_back(stdout_sink);
                }
            }
            else if (type == LogService::FILE_LOG)
            {
                auto file_sink = std::make_shared<spdlog::sinks::rotating_file_sink_mt>(
                    DEFAULT_LOGGER_FILE_PATH, DEFAULT_LOGGER_FILE_SIZE_MB * 1024 * 1024, DEFAULT_LOGGER_FILE_COUNT);
                if (file_sink)
                {
                    sinks_.push_back(file_sink);
                }
            }
            else if (type == LogService::UDP_LOG)
            {
                spdlog::sinks::udp_sink_config cfg(DEFAULT_LOGGER_IP, DEFAULT_LOGGER_PORT);
                auto udp_sink = std::make_shared<spdlog::sinks::udp_sink_mt>(cfg);
                if (udp_sink)
                {
                    sinks_.push_back(udp_sink);
                }
            }
            else if (type == LogService::COLOR_LOG)
            {
                auto color_sink = std::make_shared<spdlog::sinks::stdout_color_sink_mt>();
                if (color_sink)
                {
                    sinks_.push_back(color_sink);
                }
            }
            else
            {
                /* error, unkown log type */
            }
        }
        if (sinks_.size() == 0)
        {
            // std::cerr << "log service init failed: paremeter error!" << std::endl;
            return -3;
        }
        for (auto &sink : sinks_)
        {
            sink->set_pattern(pattern_);
        }
        default_logger = std::make_shared<spdlog::logger>("main", sinks_.begin(), sinks_.end());
        if (default_logger) {
            default_logger->set_level(spdlog::level::level_enum::info);
        }
    }
    catch (const spdlog::spdlog_ex &ex)
    {
        // std::cerr << "log service init failed: " << ex.what() << std::endl;
        return -4;
    }
    catch (...)
    {
        // std::cerr << "log service init failed: unknown error" << std::endl;
        return -5;
    }
    return 0;
}

